package baiqitun.stupro.common.service.support;

import baiqitun.stupro.common.entity.TreeNode;
import baiqitun.stupro.common.exception.support.NotFoundException;
import baiqitun.stupro.common.model.TreeModel;
import baiqitun.stupro.common.service.TreeNodeService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author kedaji
 * @param <M> Mapper接口
 * @param <T> 实体类
 */
public class TreeNodeServiceImpl<M extends BaseMapper<T>, T extends TreeNode> extends MyServiceImpl<M, T> implements TreeNodeService<T>{
    @Autowired
    private IService<T> service;

    @Override
    public TreeModel<T> getTree(String id) {
        TreeModel<T> tree = new TreeModel<>();
        List<TreeModel<T>> childTrees = new LinkedList<>();
        for (T entity: getChildren(id)){
            childTrees.add(getTree(entity.getId()));
        }
        tree.setNode(service.getById(id)).setChildrenTree(childTrees);
        return tree;
    }

    @Override
    public TreeModel<T> getTree(String id, T queryEntity, Map<String, Object> conditions) {
        TreeModel<T> tree = new TreeModel<>();
        List<TreeModel<T>> childTrees = new LinkedList<>();
        for (T entity: getChildren(id, queryEntity, conditions)){
            childTrees.add(getTree(entity.getId()));
        }
        tree.setNode(service.getById(id)).setChildrenTree(childTrees);
        return tree;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public T getTopNode(String id, T queryEntity) {
        T node = service.getById(id);
        if (node == null){
            throw new NotFoundException().put("id", id);
        }
        while (StringUtils.isNotBlank(node.getParentId())){
            node = service.getById(node.getParentId());
        }
        return node;
    }

    @Override
    public List<TreeModel<T>> listRootTree() {
        LinkedList<TreeModel<T>> trees = new LinkedList<>();
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("parent_id");
        List<T> entities = list(queryWrapper);
        for (T tmpEntity : entities){
            TreeModel<T> tree = getTree(tmpEntity.getId());
            trees.add(tree);
        }
        return trees;
    }

    @Override
    public List<TreeModel<T>> listRootTree(T queryEntity, Map<String, Object> conditions) {
        LinkedList<TreeModel<T>> trees = new LinkedList<>();
        List<T> entities = list(new QueryWrapper<T>().isNull("parent_id"));
        for (T tmpEntity : entities){
            TreeModel<T> tree = getTree(tmpEntity.getId());
            trees.add(tree);
        }
        return trees;
    }

    protected List<T> getChildren(String id){
        return service.list(new QueryWrapper<T>().eq("parent_id", id));
    }

    /**
     * 使用到此方法时请在子类重写此方法
     * @param id 节点id
     * @param queryEntity 查询条件实体
     * @return 符合条件的数据列表
     */
    protected List<T> getChildren(String id, T queryEntity, Map<String, Object> conditions){
        return service.list(new QueryWrapper<T>(queryEntity).eq("parent_id", id));
    }

}
